package com.yltrcc.blog.business.impl;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yltrcc.blog.generate.domain.*;
import com.yltrcc.blog.generate.mapper.*;
import com.yltrcc.blog.generate.mapper.custom.ArticleMapperCustom;
import com.yltrcc.blog.generate.mapper.custom.CategoryMapperCustom;
import com.yltrcc.blog.generate.mapper.custom.TagMapperCustom;
import com.yltrcc.blog.generate.mapper.generator.ArticleMapper;
import com.yltrcc.blog.model.domain.ArticleCustom;
import com.yltrcc.blog.model.model.ArchiveBo;
import com.yltrcc.blog.model.enums.ArticleStatus;
import com.yltrcc.blog.business.ArticleService;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.yltrcc.blog.generate.mapper.generator.ArticleCategoryMapper;
import com.yltrcc.blog.generate.mapper.generator.ArticleTagMapper;
import com.yltrcc.blog.model.enums.PostType;

import cn.hutool.core.date.DateUtil;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;

import static java.util.stream.Collectors.toMap;
import static java.util.stream.Collectors.toSet;

/**
 * @author yltrcc
 * @createDate : 2018年10月15日
 */
@Service
@Transactional(rollbackFor = RuntimeException.class)
public class ArticleBusinessServiceImpl implements ArticleService {

    private static final String ARTICLES_CACHE_KEY = "'article'";

    private static final String ARTICLES_CACHE_NAME = "articles";
    @Resource
    private ArticleMapper articleMapper;
    @Resource
    private ArticleTagMapper articleTagMapper;
    @Resource
    private ArticleCategoryMapper articleCategoryMapper;
    @Resource
    private ArticleMapperCustom articleMapperCustom;
    @Resource
    private TagMapperCustom tagMapperCustom;
    @Resource
    private CategoryMapperCustom categoryMapperCustom;

    @Resource
    private BlogArticleMapper blogArticleMapper;

    @Resource
    private BlogArticleCategoryMapper blogArticleCategoryMapper;

    @Resource
    private BlogCategoryMapper blogCategoryMapper;

    @Resource
    private BlogArticleTagMapper blogArticleTagMapper;

    @Resource
    private BlogTagMapper blogTagMapper;

    /**
     * 自动生成的mapper里配置了useGeneratedKeys="true" keyProperty="id" 如重新生成请复制过去
     */
    @Override
    @CacheEvict(value = ARTICLES_CACHE_NAME, allEntries = true, beforeInvocation = true)
    public void save(Article article, Long[] tags, Long[] categorys) throws Exception {
        articleMapper.insert(article);
        if (categorys != null) {
            Arrays.asList(categorys).stream().forEach(cate -> {
                ArticleCategory articleCategory = new ArticleCategory();
                articleCategory.setArticleId(article.getId());
                articleCategory.setCategoryId(cate);
                articleCategoryMapper.insert(articleCategory);
            });
        }
        if (tags != null) {
            Arrays.asList(tags).stream().forEach(tag -> {
                ArticleTag articleTag = new ArticleTag();
                articleTag.setArticleId(article.getId());
                articleTag.setTagId(tag);
                articleTagMapper.insert(articleTag);
            });
        }
    }

    @Override
    @Cacheable(value = ARTICLES_CACHE_NAME, key = "'findAllArticle'+#status+#post")
    public List<BlogArticleModel> findAllArticle(int status, String post) {
        return articleMapperCustom.findAllArticle(status, post);
    }

    @Override
    public PageInfo<ArticleCustom> findPageArticle(int page, int limit, ArticleCustom articleCustom) {
        /*PageHelper.startPage(Long.valueOf(page.getCurrent()).intValue(), Long.valueOf(page.getSize()).intValue());*/
        /*List<BlogArticleModel> lists = articleMapperCustom.findPageArticle(blogArticleModel);*/
        PageHelper.startPage(page, limit);
        BlogArticleModel blogArticleModel = new BlogArticleModel();
        if (articleCustom.getId() != null) {
            blogArticleModel.setId(articleCustom.getId());
        }
        if (articleCustom.getArticlePost() != null) {
            blogArticleModel.setArticlePost(articleCustom.getArticlePost());
        }
        if (articleCustom.getArticleStatus() != null) {
            blogArticleModel.setArticleStatus(articleCustom.getArticleStatus());
        }
        // 先查询主表信息
        List<ArticleCustom> blogArticles = articleMapperCustom.findPageArticle(blogArticleModel);
        if (!blogArticles.isEmpty()) {
            return new PageInfo<>(blogArticles);
        }
        return new PageInfo<>(blogArticles);

    }

    private List<ArticleCustom> addExtraInfo(List<ArticleCustom> articleCustoms) {

        // blog_article_tag.tag_id = blog_tag.tag_id

        // 提取article id，方便批量查询
        Set<Integer> articleIds = articleCustoms.stream().map(ArticleCustom::getId).collect(toSet());

        // id -> blog_article_category article id blog_article_tag article id
        List<BlogArticleCategory> articleCategories = blogArticleCategoryMapper.selectList(Wrappers.lambdaQuery(BlogArticleCategory.class)
                .in(BlogArticleCategory::getArticleId, articleIds));
        // blog_article_category.category_id = blog_category.category_id
        List<Long> categoryIds = articleCategories.stream().map(BlogArticleCategory::getCategoryId).collect(Collectors.toList());
        List<BlogCategory> blogCategories = new ArrayList<>();
        if (!CollectionUtils.isEmpty(categoryIds)) {
            blogCategories = blogCategoryMapper.selectList(Wrappers.lambdaQuery(BlogCategory.class)
                    .in(BlogCategory::getCategoryId, categoryIds));
        }

        List<BlogArticleTag> articleTags = blogArticleTagMapper.selectList(Wrappers.lambdaQuery(BlogArticleTag.class)
                .in(BlogArticleTag::getArticleId, articleIds));
        List<Long> tagIds = articleTags.stream().map(BlogArticleTag::getTagId).collect(Collectors.toList());
        List<BlogTag> blogTags = new ArrayList<>();
        if (!CollectionUtils.isEmpty(tagIds)) {
            blogTags = blogTagMapper.selectList(Wrappers.lambdaQuery(BlogTag.class)
                    .in(BlogTag::getTagId, tagIds));
        }
        // 构造映射关系
        Map<Integer, Long> idToCategoryIdMap = articleCategories.stream()
                .collect(toMap(BlogArticleCategory::getArticleId, BlogArticleCategory::getCategoryId));
        Map<Integer, BlogCategory> categoryMap = blogCategories.stream()
                .collect(toMap(BlogCategory::getCategoryId, obj -> obj));

        Map<Integer, Long> idToTagIdMap = articleTags.stream()
                .collect(toMap(BlogArticleTag::getArticleId, BlogArticleTag::getTagId));
        Map<Integer, BlogTag> TagMap = blogTags.stream()
                .collect(toMap(BlogTag::getTagId, obj -> obj));
        // 将查询补充的信息添加到Vo中

        return articleCustoms.stream().peek(u -> {
            u.setCategorys(String.valueOf(idToCategoryIdMap.get(u.getId())));
            Long categoryId = idToCategoryIdMap.get(u.getId());
            if (null != categoryId) {
                u.setCategorysName(categoryMap.get(categoryId.intValue()).getCategoryName());
                u.setCategorysUrl(categoryMap.get(categoryId.intValue()).getCategoryUrl());
            }
            Long tagId = idToTagIdMap.get(u.getId());
            if (null != tagId) {
                u.setTags(String.valueOf(tagId));
                u.setTagsName(TagMap.get(tagId.intValue()).getTagName());
                u.setTagsUrl(TagMap.get(tagId.intValue()).getTagUrl());
            }
        }).collect(Collectors.toList());
    }

    @Override
    @Cacheable(value = ARTICLES_CACHE_NAME, key = "'Post_status'+#status+#post")
    public Integer countByStatus(Integer status, String post) {
        return articleMapperCustom.countByStatus(status, post);
    }

    @Override
    @CacheEvict(value = ARTICLES_CACHE_NAME, allEntries = true, beforeInvocation = true)
    public void recycle(int id, Integer integer) throws Exception {
        articleMapperCustom.updateStatus(id, integer);
    }

    @Override
    @CacheEvict(value = ARTICLES_CACHE_NAME, allEntries = true, beforeInvocation = true)
    public void remove(int id) throws Exception {
        // 删除文章表
        articleMapper.deleteByPrimaryKey(id);
        ArticleTagExample articleTagexample = new ArticleTagExample();
        ArticleTagExample.Criteria tagCriteria = articleTagexample.createCriteria();
        tagCriteria.andArticleIdEqualTo(id);
        ArticleCategoryExample articleCategoryExample = new ArticleCategoryExample();
        ArticleCategoryExample.Criteria categoryCriteria = articleCategoryExample.createCriteria();
        categoryCriteria.andArticleIdEqualTo(id);
        // 删除分类表和标签表
        articleTagMapper.deleteByExample(articleTagexample);
        articleCategoryMapper.deleteByExample(articleCategoryExample);
    }

    @Override
    @Cacheable(value = ARTICLES_CACHE_NAME, key = "'findByArticleId'+#article_id")
    public BlogArticleModel findByArticleId(Integer article_id) {
        return articleMapperCustom.findByArticleId(article_id);
    }

    @Override
    @CacheEvict(value = ARTICLES_CACHE_NAME, allEntries = true, beforeInvocation = true)
    public void update(Article article, Long[] tags, Long[] categorys) throws Exception {
        // 修改文章
        articleMapper.updateByPrimaryKeySelective(article);
        // 先查出关联的分类与标签
        List<Integer> tagList = tagMapperCustom.selectByarticleId(article.getId());
        List<Integer> cateList = categoryMapperCustom.selectByarticleId(article.getId());
        if (tagList != null && tagList.size() > 0) {
            // 然后删除
            tagMapperCustom.delete(tagList, article.getId());
        }
        if (cateList != null && cateList.size() > 0) {
            categoryMapperCustom.delete(cateList, article.getId());
        }
        // 再添加
        // 鬼知道我最开始为什么这样子设计。。。等到都写完了就不愿意改了，先用着吧
        if (categorys != null) {
            Arrays.asList(categorys).stream().forEach(cate -> {
                ArticleCategory articleCategory = new ArticleCategory();
                articleCategory.setArticleId(article.getId());
                articleCategory.setCategoryId(cate);
                articleCategoryMapper.insert(articleCategory);
            });
        }
        if (tags != null) {
            Arrays.asList(tags).stream().forEach(tag -> {
                ArticleTag articleTag = new ArticleTag();
                articleTag.setArticleId(article.getId());
                articleTag.setTagId(tag);
                articleTagMapper.insert(articleTag);
            });
        }
    }

    @Override
    @Cacheable(value = ARTICLES_CACHE_NAME, key = ARTICLES_CACHE_KEY)
    public List<ArchiveBo> archives() {
        // 查询文章表各个时间段的文章数量 分别为DATE->时间段 count->文章数量
        List<ArchiveBo> listforArchiveBo = articleMapperCustom.findDateAndCount();
        if (listforArchiveBo != null) {
            for (ArchiveBo archiveBo : listforArchiveBo) {
                ArticleExample example = new ArticleExample();
                // 在EXAMPLE对象中存放article_status和article_post
                ArticleExample.Criteria criteria = example.createCriteria().andArticleStatusEqualTo(0)
                        .andArticlePostEqualTo("post");
                example.setOrderByClause("article_newstime desc");
                String date = archiveBo.getDate();
                Date sd = DateUtil.parse(date, "yyyy年MM月");
                // 在criteria对象中放入article_newstime大于或者等于的值
                criteria.andArticleNewstimeGreaterThanOrEqualTo(sd);
                Calendar cal = Calendar.getInstance();
                // 判断获取的时间的月份是否小于12
                if (sd.getMonth() < 12) {
                    cal.setTime(sd);
                    // 月份 +1
                    cal.add(Calendar.MONTH, +1);
                } else {
                    cal.setTime(sd);
                    // 年 +1
                    cal.add(Calendar.YEAR, +1);
                }
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月");
                String date2 = sdf.format(cal.getTime());
                Date date3 = DateUtil.parse(date2, "yyyy年MM月");
                // 在criteria对象中放入article_newstime小于的值
                criteria.andArticleNewstimeLessThan(date3);
                List<Article> articles = articleMapper.selectByExample(example);
                archiveBo.setArticles(articles);
            }
        }
        return listforArchiveBo;
    }

    @Override
    @Cacheable(value = ARTICLES_CACHE_NAME, key = "'articleUrlInt'+#articleUrl")
    public int findRepeatByUrl(String articleUrl) {
        return articleMapperCustom.findRepeatByUrl(articleUrl);
    }

    @Override
    @Cacheable(value = ARTICLES_CACHE_NAME, key = "'articleUrl'+#articleUrl")
    public BlogArticleModel findByArticleUrl(String articleUrl) {
        return articleMapperCustom.findByArticleUrl(articleUrl);
    }

    @Override
    @Cacheable(value = ARTICLES_CACHE_NAME, key = "'findArtileByCategory'+#page+#limit+#category.categoryUrl")
    public PageInfo<BlogArticleModel> findArtileByCategory(int page, int limit, Category category, int status) {
        PageHelper.startPage(page, limit);
        List<BlogArticleModel> list = articleMapperCustom.findArtileByCategory(category, status);
        return new PageInfo<>(list);
    }

    @Override
    public List<BlogArticleModel> findArtileByCategoryId(Category category, int status) {
        return articleMapperCustom.findArtileByCategoryId(category, status);
    }

    @Override
    @Cacheable(value = ARTICLES_CACHE_NAME, key = "'findArtileByTag'+#page+#limit+#status+#tag.tagUrl")
    public PageInfo<BlogArticleModel> findArtileByTag(Integer page, Integer limit, Tag tag, int status) {
        PageHelper.startPage(page, limit);
        List<BlogArticleModel> list = articleMapperCustom.findArtileByTag(tag, status);
        return new PageInfo<>(list);
    }

    @Override
    @Cacheable(value = ARTICLES_CACHE_NAME, key = "'findArticleByKeywords'+#keywords+#page+#limit")
    public PageInfo<Article> findArticleByKeywords(String keywords, Integer page, Integer limit) {
        PageHelper.startPage(page, limit);
        ArticleExample articleExample = new ArticleExample();
        ArticleExample.Criteria criteria = articleExample.createCriteria();
        criteria.andArticlePostEqualTo(PostType.POST_TYPE_POST.getValue());
        criteria.andArticleStatusEqualTo(ArticleStatus.PUBLISH.getStatus());
        criteria.andArticleTitleLike("%" + keywords + "%");
        articleExample.setOrderByClause("article_newstime desc");
        List<Article> list = articleMapper.selectByExample(articleExample);
        return new PageInfo<>(list);
    }

    @Override
    @CacheEvict(value = ARTICLES_CACHE_NAME, allEntries = true, beforeInvocation = true)
    public void updateArticleViews(Article article) {
        articleMapper.updateByPrimaryKeySelective(article);
    }
}
